import pygame
import random
"""
贪吃蛇开发：

1. 把蛇身和食物绘制出来（优化）
2. 能让蛇身动起来（上下左右）
    a. 将蛇头复制一份
    b. 复制的蛇头向当前方向移动一格
    c. 把新的蛇头插入到头部
    d. 删除蛇尾即可
3. 根据用户键盘输入修改运动方向
4. 碰撞判断：蛇头与食物
    a. 蛇身长一节
    b. 食物随机生成到新的位置
5. 碰撞判断：蛇头与墙体/身体
    a. 蛇头碰到墙体
    b. 蛇头碰到身体
6. 实时分数和FPS(Frame Per second)显示
7. 结束提示：得分，按键重新开始

额外功能
1.从屏幕另一端出现
2.分数越高，速度加快
"""
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480

COLOR_GRAY = (150,150,150)
COLOR_WHITE= (255,255,255)
COLOR_BLUE= (0,0,255)
COLOR_RED= (255,0,0)

BLOCK_SIZE = 20

DIRECTION_DICT={
    pygame.K_UP:(0,-BLOCK_SIZE),#上
    pygame.K_RIGHT:(BLOCK_SIZE ,0),#右
    pygame.K_DOWN:(0, BLOCK_SIZE),#下
    pygame.K_LEFT:(-BLOCK_SIZE,0),#左             
}

class Snake:
    def __init__(self,x,y) -> None:
        self.direction = pygame.K_LEFT  #0上 1右 2下 3左
        self.is_cross_enable = True
        self.snake_body = [
            pygame.Rect(x * BLOCK_SIZE,y*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE),
        ] 
        head_image = pygame.image.load("res/微信图片_20241030124558.jpg")
        #缩放
        self.snake_head_image=pygame.transform.scale(head_image,(BLOCK_SIZE,BLOCK_SIZE))
        
        self.score = 0
        for _ in range(5):
            self.grow()
        
    def draw(self,screen):
        
        #绘制蛇身体
        for node in self.snake_body[1:]:
                pygame.draw.rect(screen,COLOR_WHITE,node,width=4,border_radius=3)
        HEAD_DICT ={
            pygame.K_DOWN : 0,
            pygame.K_UP: 180,
            pygame.K_LEFT : 270,
            pygame.K_RIGHT: 90,
            
        } 
        #绘制蛇头
        head: pygame.Rect = self.snake_body[0]
        #对原始的头旋转 ：
        # Right->90
        # Down ->0
        # UP   ->180 
        # Left ->270  
        head_image = pygame.transform.rotate(self.snake_head_image,HEAD_DICT[self.direction])
        screen.blit(head_image,(head.x,head.y))
        
        
    def is_direction_enable(self,input_key):
        if input_key not in (pygame.K_RIGHT, pygame.K_LEFT,pygame.K_UP,pygame.K_DOWN):
            return False
        
        LR = (pygame.K_RIGHT, pygame.K_LEFT)
        if self.direction in LR and input_key in LR :
            return False
        UP = (pygame.K_UP,pygame.K_DOWN)
        if self.direction in UP and input_key in UP :
            return False
        return True
    
    
    def update_direction(self,input_key):
        #禁止水平或竖直方向直接转换
        #蛇不能原地掉头（不能左右）
        #蛇不能原地掉头（不能向上）
       

        
        self.direction = input_key
    
    
    def move(self):
        new_node = self.snake_body[0].copy()
        new_move = DIRECTION_DICT[self.direction]
        new_node.x += new_move[0]
        new_node.y += new_move[1]
        
        
        if self.is_cross_enable:
            
            #如果超出范围，瞬移
            if new_node.x >= SCREEN_WIDTH:
                new_node.x -= SCREEN_WIDTH
            elif new_node.x < 0:
                new_node.x += SCREEN_WIDTH

            if new_node.y >= SCREEN_HEIGHT:
                new_node.y -= SCREEN_HEIGHT
            elif new_node.y<0:
                new_node.y += SCREEN_HEIGHT
    
         
        #把新的蛇头放在最前面
        self.snake_body.insert(0,new_node)
        #删除蛇尾巴
        self.snake_body.pop()

    def grow(self):
        #复制蛇尾
        new_node = self.snake_body[-1].copy()
        self.snake_body.append(new_node)
        
        #得1分
        self.score += 1

class Food:
    def __init__(self,node) -> None:
        self.node = node
    
    def draw(self,screen):
        pygame.draw.rect(screen,COLOR_BLUE,self.node,border_radius=3)
        
    @staticmethod
    def gen_food_positison(snake:Snake):
        while True:
            
            x = random.randint(0,SCREEN_WIDTH // BLOCK_SIZE-1)
            
            y = random.randint(0,SCREEN_HEIGHT // BLOCK_SIZE-1)
            
            new_food_node = pygame.Rect(x * BLOCK_SIZE,y * BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE)
            
            if new_food_node not in snake.snake_body:
                #新的食物不在蛇身和蛇头
                return new_food_node

        
class Game:
    def __init__(self) -> None:
        pygame.init()
        
        pygame.display.set_caption("贪吃蛇大战v1.0")

        self.screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))

        icon = pygame.image.load("res/icon.png")

        pygame.display.set_icon(icon)

        bg_image = pygame.image.load("res/bg.png")
        #缩放
        self.bg_image = pygame.transform.scale(bg_image,(SCREEN_WIDTH,SCREEN_HEIGHT))

    def start(self):
        
        is_game_over = False    
        clock = pygame.time.Clock()
        snake = Snake(3,5)
        food = Food(Food.gen_food_positison(snake))

        while True:
            #处理事件，获取用户输入的事件
            event_list = pygame.event.get()
            new_dir = None
            #解析处理所有的事件
            #event.type 保存了用户输入的事件类型 :鼠标。案件
            #event.key 保存了按下或抬起的按键
            for event in event_list:
                if event.type == pygame.QUIT:
                    print("点击了关闭")
                    #退出游戏
                    pygame.display.quit()
                    exit(0)
                elif event.type == pygame.KEYDOWN:
                    print("按键按下：",event.key)
                    if is_game_over :
                        if event.key == pygame.K_q:
                            self.quit_game()
                        elif event.key == pygame.K_SPACE:
                            snake = Snake(5,8)
                            food = Food(Food.gen_food_positison(snake))
                            is_game_over = False   
                                
                    #上。下。左。右。空格
                    

                    elif   event.key == pygame.K_ESCAPE:  
                        print("关闭")
                        self.quit_game()
                    elif snake.is_direction_enable(event.key):
                        new_dir = event.key
            if new_dir is not None:
                     snake.update_direction(new_dir )        
            
            
            self.screen.blit(self.bg_image,(0,0))   
            #网格线
            #pygame.draw.line( screen,COLOR_GRAY,(0,0),(300,100),1)
            #绘制所有的横线  h = 480 //20 = 24 [2,20,40,........480]
            for y in range (0,SCREEN_HEIGHT,BLOCK_SIZE):
                pygame.draw.line(self.screen,COLOR_GRAY,(0,y),(SCREEN_WIDTH,y))
            #绘制所有的竖线  w = 640 //20 = 32 [2,20,40,........640]
            for x in range (0,SCREEN_WIDTH,BLOCK_SIZE):
                pygame.draw.line(self.screen,COLOR_GRAY,(x,0),(x,SCREEN_WIDTH))

            #绘制蛇身
            snake.draw(self.screen)
            if not is_game_over:
                    
                snake.move()
                
                #遇到食物，吃掉，身体长一节
                snake_head = snake.snake_body[0]
                if snake.snake_body[0] == food.node:
                    #吃掉食物，刷新食物
                    food = Food(Food.gen_food_positison(snake))
                    #蛇身变长
                    snake.grow()
                    
                #碰到墙壁
                if snake_head.x < 0 or snake_head.x >= SCREEN_WIDTH \
                    or snake_head.y<0 or snake_head.y>=SCREEN_HEIGHT: 
                    is_game_over = True
                    
                
                #碰到自己
                if snake_head in snake.snake_body[1:]:
                    is_game_over = True
                    
                if is_game_over:
                    self.show_text("游戏结束",50,SCREEN_WIDTH//4,SCREEN_HEIGHT//4)
                    self.show_text("得分",24,SCREEN_WIDTH//4,SCREEN_HEIGHT//4+60)
                    self.show_text("按任意键重新开始",24,SCREEN_WIDTH//4,SCREEN_HEIGHT//4+90)
                    self.show_text("按Q退出游戏",24,SCREEN_WIDTH//4,SCREEN_HEIGHT//4+120)
                    
                #绘制食物
                food.draw(self.screen)

                #绘制得分和fps
                fps = clock.get_fps()
                self.show_text("FPS: {:.2f}".format(fps),20,SCREEN_WIDTH-200,10)
                
                self.show_text("Score: {}".format(snake.score),20,10,10)
                #刷新界面

                pygame.display.flip()  
                        
                clock.tick(5+snake.score)

    def quit_game(self):
        pygame.display.quit()
        exit(0)
            
    def show_text(self,text,font_size,x,y):
        font1 = pygame.font.SysFont('Simhei',font_size)
        text = font1.render(text,True,COLOR_RED)  
        self.screen.blit(text,(x,y))
                            
game = Game()
game.start()
                    